Skip to content

Improve access token handling#8

Merged
aaronskiba merged 15 commits intodevelopmentfrom
improve-access-token-handling
Mar 18, 2026
Merged

Improve access token handling#8
aaronskiba merged 15 commits intodevelopmentfrom
improve-access-token-handling

Conversation

@aaronskiba
Copy link
Owner

@aaronskiba aaronskiba commented Mar 7, 2026

Overview

This PR adds access token refresh logic to AuthContext.useFetch, a newly added custom hook, has been created to centralize async data fetching from Spotify. The access token handling logic has been integrated with useFetch.

Other features (Loader and ErrorMessage components) have been added. Several bugfixes (useAuth() destructuring and null-safe handling for playlist.images) are included, and much refactoring has been performed as well.

With the exception of `SpotifyPlaylistActions`, moved all prop type definitions from `src/types/SpotifyPlaylistProps.ts` to the components that actually use them.
It is possible for `playlist.images == null`. This change adds null-safe handling whenever attempting to access `playlist.images[0].url`.
This refactor centralizes and generalizes async data fetching, reducing duplication and simplifying component logic.

Create custom `useFetch` hook (`src/hooks/useFetch.ts`)
- Move data-fetching logic from components into reusable hook
- Remove local useEffect-based fetch implementations from:
  - `src/components/CompareTracks.tsx`
  - `src/components/Playlists.tsx`
  - `src/components/PlaylistTracks.tsx`
- Remove component-level useState related to fetching

TODO / Follow-up work:
- Add error handling support
- Add isLoading state handling
- Introduce request cancellation via AbortController
Add AbortController and cleanup logic to useFetch
- Pass AbortSignal to fetchFn and underlying fetch calls

Update components using useFetch to receive `AbortSignal`

Update services to accept optional `signal?: AbortSignal`:
- playlistService.ts
- spotifyApi.ts
- trackService.ts
- Refactor `useFetch` to return `data = null` unless a request completes successfully

- Introduce `ErrorMessage` component for rendering Spotify API errors

- Update `useFetch` consumers to explicitly handle loading, error, and data states

- Render `<ErrorMessage />` when error is present

- Render data components only when data is non-null
Add src/hooks/useFetchSpotify.ts

Add useFetchPlaylists and useFetchTracks custom hooks

Composes Spotify service calls with generic useFetch

Removes fetch wiring logic from UI components
- Within `useFetch`, add `isLoading` to `fetchState`.
- Add Loader component
- Use Loader component within components that rely on `useFetch`
Update `AuthContext`
- Provide `accessToken` (string|null), rather than full `auth` object
  - `isAuthenticated` boolean is now based off of `accessToken` presence
  - Update corresponding components (`Playlists`, `PlaylistTracks`, `CompareTracks`) to now read `accessToken`
  - Update `useFetchPlaylists` and `useFetchTracks` to handle null `accessToken`
- Add a small token expiry buffer and `isExpiredToken` helper
- Add `setAuth(null)` within login error.
@aaronskiba aaronskiba force-pushed the improve-access-token-handling branch 3 times, most recently from 5924a5e to cbae38c Compare March 15, 2026 02:48
@aaronskiba aaronskiba force-pushed the improve-access-token-handling branch from cbae38c to 3395989 Compare March 17, 2026 06:06
Add token refresh logic to AuthContext, and integrate valid access token handling with useFetch. This change allows us to stop passing access tokens throughout the app

Key changes:
- `AuthContext` now exposes `getValidAccessToken()` which auto-refreshes expired tokens, updates context state, and prevents concurrent refreshes via a ref.
- Added `src/utils/authToken.ts` with `isValidToken`, `getAccessTokenExpirationDate`, and `getUpdatedAuthFromRefreshResponse` helpers.
- Added `getRefreshToken()` in `src/services/authService.ts` to call Spotify's token endpoint and added `SpotifyRefreshResponse` type (`src/types/SpotifyAuth.ts`).
- `useFetch` now retrieves a valid access token via `useAuth` and passes it to fetch functions; `fetchFn` signature changed to `(accessToken, signal)`.
  - Updated `useFetchSpotify` hooks (`useFetchPlaylists`, `useFetchTracks`) and components (Playlists, PlaylistTracks, CompareTracks) to correspond with these changes

This change centralizes token handling, prevents duplicate refresh requests, and simplifies component usage.
- Add `src/utils/spotifyImages.ts` with `getUriFromImages(images)`
- Rename `Header` prop `images: string[] → imageUris: Array<string | null>` and normalize inside `Header` by trimming and filtering falsy/empty URIs before rendering.
- Update `<Image>` call sites to only render when `getUriFromImages(...)` returns a non-null URI.
- Update `Header` call sites to pass `imageUris={[getUriFromImages(...)]}` (and rely on Header sanitization).
These changes correspond with the recommended `GET /playlists/{playlist_id}/items` call for fetching tracks.

https://developer.spotify.com/documentation/web-api/reference/get-playlists-tracks states that `GET /playlists/{playlist_id}/tracks` is deprecated.
@aaronskiba aaronskiba force-pushed the improve-access-token-handling branch from 3395989 to 8db285e Compare March 18, 2026 01:25
@aaronskiba aaronskiba marked this pull request as ready for review March 18, 2026 01:26
@aaronskiba aaronskiba merged commit 0c33848 into development Mar 18, 2026
1 check passed
@aaronskiba aaronskiba deleted the improve-access-token-handling branch March 18, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant